/**
  * Copyright (c) CSIRO Australia, 2009
  *
  * @author $Author: jia020 $
  * @version $Id: XMLParamsParser.java 643 2009-05-20 00:20:55Z jia020 $
  */
package au.csiro.nt.pdsp.util;

import java.io.*;
import java.util.HashMap;
import java.util.Map;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.xml.sax.*;

import org.w3c.dom.*;

/**
 * Parser for XML Document Type Params.
 * 
 * An example of this is: <span> <code>
* <params><param id="1" key="DBNAME" value="pdsp"><param id="2" key="DBPIN" value="xxx"></param></params>
* </code> </span>
 * 
 * @author jia020
 */
public class XMLParamsParser {

	/**
	 * Map to hold all the key-value pairs of each parameter.
	 */
	Map<String, String> mapParams = null;

	/**
	 * XML element name that represents a single parameter.
	 */
	private final String XML_TAG = "param";

	/**
	 * The XML attribute of a parmeter that contains the key.
	 */
	private final String KEY_XML_ATTR = "key";

	/**
	 * The XML attribute of a parmeter that contains the value.
	 */
	private final String VALUE_XML_ATTR = "value";

	/**
	 * Default constructor.
	 */
	public XMLParamsParser() {
		this.mapParams = new HashMap<String, String>();

	} // End of default constructor.

	/**
	 * Returns the <b>reference</b> to a {@link java.util.Map} that contains the
	 * parameters.
	 * 
	 * @return {@link java.util.Map} <b>Reference</b> to parameters represented as
	 *         key-value pairs.
	 */
	public Map<String, String> getMap() {
		return this.mapParams;

	} // End of `ProtocolParams.getMap` method.

	/**
	 * Get value of parameter by a key
	 * 
	 * @param key
	 *          Name of parameter to look for.
	 * 
	 * @return value Value of parameter corresponding to the supplied
	 *         <code>key</code> as a {@link java.lang.String}. <code>null</code>
	 *         if value is not found.
	 */
	public String getParam(String key) {
		if (mapParams != null) {
			return mapParams.get(key);
		} else {
			return null;
		}

	} // End of `ProtocolParams.getParam` method.

	/**
	 * Loads parameters from an {@link java.io.InputSource} that is referencing
	 * the parameters XML.
	 * 
	 * @param input
	 *          {@link java.io.InputSource} that is referencing the XML parameter.
	 * 
	 * @return Number of parameters found and loaded.
	 * 
	 * @throws {@link java.io.IOException} Failed to load or parse XML parameters.
	 */
	public int loadParams(InputSource input) throws IOException {
		int size = 0;

		// Clears the current Map object.
		// TODO: This could cause problem because the `getMap` already
		// returned a reference to some other client of this class.
		// That is, if this clearing is done, clients of this class using
		// the Map object will have a stale object.
		// Suggestion: return a copy of the Map object instead.
		if (this.mapParams != null && this.mapParams.size() > 0) {
			this.mapParams.clear();
		}

		/**
		 * Use DOM to parse the XML string and extract the parameters.
		 */
		DocumentBuilderFactory dBF = DocumentBuilderFactory.newInstance();
		dBF.setNamespaceAware(true);
		dBF.setIgnoringComments(true);

		DocumentBuilder builder = null;
		try {
			builder = dBF.newDocumentBuilder();
		} catch (ParserConfigurationException e) {
			throw new IOException(e.getMessage(), e);
		}
		Document doc;
		try {
			doc = builder.parse(input);
		} catch (SAXException e) {
			throw new IOException(e.getMessage(), e);
		}

		NodeList nodes = doc.getElementsByTagName(XML_TAG);

		if (nodes != null && nodes.getLength() > 0) {
			String key = null;
			String value = null;
			for (int i = 0; i < nodes.getLength(); i++) {
				Node node = nodes.item(i);
				key = node.getAttributes().getNamedItem(this.KEY_XML_ATTR)
						.getNodeValue();
				value = node.getAttributes().getNamedItem(this.VALUE_XML_ATTR)
						.getNodeValue();
				mapParams.put(key, value);
				size++;
			}
		}
		return size;

	} // End of `XMLParamsParser.loadParams` method.

	/**
	 * Load parameters from represented as a {@link java.lang.String}
	 * 
	 * @param xmlParams
	 *          The parameters in an XML String.
	 * 
	 * @return Number of parameters found and loaded.
	 * 
	 * @throws {@link java.io.IOException} Failed to load or parse XML parameters.
	 */
	public int loadParams(String xmlParams) throws IOException {
		return loadParams(new InputSource(new StringReader(xmlParams)));

	} // End of `XMLParamsParser.loadParams` method.

	public static void main(String args[]) {
		XMLParamsParser parser = new XMLParamsParser();
		try {
//			<params>
//			<param id="1" key="DBNAME" value="pdsp"/>
//			<param id="2" key="DBPIN" value="xxx"/>
//			</params>
			parser.loadParams(new InputSource("d:\\pdsp-config.xml"));
			System.out.println(parser.getParam("DBNAME"));
			System.out.println(parser.getParam("DBPIN"));			
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
} // End of `XMLParamsParser` class
